"use strict";
let EOffCanvas = function (selector, options) {
    // 目标元素
    let the = this;

    // 查找对象
    let $element = $(selector);
    let $body = $('body');

    if (!$element.length) {
        return;
    }

    // 默认设置
    let defaultOptions = {};

    // 私有方法
    let Plugin = {
        construct: function (options) {
            if (EUtil.data($element).has('offCanvas')) {
                // 如果已经初始化，直接从缓存获取对象
                the = EUtil.data($element).get('offCanvas');
            } else {
                // 初始化插件
                Plugin.init(options);
                // 绑定事件
                Plugin.build();
                EUtil.data($element).set('offCanvas', the);
            }
            return the;
        },

        /**
         * 初始化
         *
         * @param options {object} option
         */
        init: function (options) {
            // 事件
            the.events = [];

            // 合并默认选项&传入option
            the.options = $.extend(true, {}, defaultOptions, options);
            // base
            the.classBase = the.options.baseClass;
            // 显示状态
            the.classShown = the.classBase + '--on';
            // 隐藏状态
            the.classOverlay = the.classBase + '-overlay';
            // 当前显示状态
            the.state = $element.hasClass(the.classShown) ? 'shown' : 'hidden';
        },
        /**
         * 绑定事件
         */
        build: function () {
            // off-canvas toggle
            if (the.options.toggleBy) {
                if (typeof the.options.toggleBy === 'string') {
                    // 如果传入的是String，表示传入的是选择器
                    $(the.options.toggleBy).click(function (e) {
                        e.preventDefault();
                        Plugin.toggle();
                    });
                } else if (the.options.toggleBy && the.options.toggleBy[0]) {
                    // 传入的是对象
                    if (the.options.toggleBy[0].target) {
                        // 指定了target属性，将事件绑定在target元素上
                        for (let i in the.options.toggleBy) {
                            $(the.options.toggleBy[i].target).click(function (e) {
                                e.preventDefault();
                                Plugin.toggle();
                            });
                        }
                    } else {
                        for (let i in the.options.toggleBy) {
                            $(the.options.toggleBy[i]).click(function (e) {
                                e.preventDefault();
                                Plugin.toggle();
                            });
                        }
                    }
                } else if (the.options.toggleBy && the.options.toggleBy.target) {
                    $(the.options.toggleBy.target).click(function (e) {
                        e.preventDefault();
                        Plugin.toggle();
                    });
                }
            }

            // off-canvas 关闭
            let $close = $(the.options.closeBy);
            if ($close.length) {
                $close.click(function (e) {
                    e.preventDefault();
                    Plugin.hide();
                });
            }
        },
        /**
         * 当前是否是显示状态
         *
         * @returns {boolean} true/false
         */
        isShown: function () {
            return the.state === 'shown';
        },
        /**
         * 切换显示&隐藏
         */
        toggle: function () {
            Plugin.eventTrigger('toggle');
            if (Plugin.isShown()) {
                Plugin.hide(this);
            } else {
                Plugin.show(this);
            }
        },
        /**
         * 显示
         *
         * @param target
         */
        show: function (target) {
            if (Plugin.isShown()) {
                // 如果当前是显示状态，跳过
                return;
            }
            // 执行显示前回调
            Plugin.eventTrigger('beforeShow');
            // 设置状态为显示
            Plugin.togglerClass(target, 'show');

            // off-canvas panel
            $body.addClass(the.classShown);
            $element.addClass(the.classShown);
            // 将状态属性设置为显示
            the.state = 'shown';

            // 是否需要灰色遮罩层
            if (the.options.overlay) {
                // 插入遮罩div
                the.overlay = $('<div/>').prependTo($body);
                the.overlay.addClass(the.classOverlay);
                the.overlay.click(function (e) {
                    e.stopPropagation();
                    e.preventDefault();
                    Plugin.hide(target);
                });
            }
            // 执行显示后回调
            Plugin.eventTrigger('afterShow');
        },

        hide: function (target) {
            if (!Plugin.isShown()) {
                return;
            }

            // 执行隐藏前回调
            Plugin.eventTrigger('beforeHide');
            // 设置状态为隐藏
            Plugin.togglerClass(target, 'hide');

            $body.removeClass(the.classShown);
            $element.removeClass(the.classShown);
            the.state = 'hidden';

            if (the.options.overlay && the.overlay) {
                the.overlay.remove();
            }

            Plugin.eventTrigger('afterHide');
        },

        /**
         * 更改显示&隐藏class
         *
         * @param target {object} 目标
         * @param mode {string} 要切换成的模式
         */
        togglerClass: function (target, mode) {
            let id = $(target).attr('id');
            let toggleBy;

            if (the.options.toggleBy && the.options.toggleBy[0] && the.options.toggleBy[0].target) {
                for (let i in the.options.toggleBy) {
                    if (the.options.toggleBy[i].target === id) {
                        toggleBy = the.options.toggleBy[i];
                    }
                }
            } else if (the.options.toggleBy && the.options.toggleBy.target) {
                toggleBy = the.options.toggleBy;
            }

            if (toggleBy) {
                let el = $(toggleBy.target);

                if (mode === 'show') {
                    el.addClass(toggleBy.state);
                }

                if (mode === 'hide') {
                    el.removeClass(toggleBy.state);
                }
            }
        },

        /**
         * 触发事件
         *
         * @param name {string} 事件名称
         * @param args {object} 参数
         */
        eventTrigger: function (name, args) {
            for (let i = 0; i < the.events.length; i++) {
                let event = the.events[i];
                if (event.name === name) {
                    if (event.one) {
                        // 一次性事件
                        if (!event.fired) {
                            // 设置事件属性为已触发，下次不执行
                            the.events[i].fired = true;
                            event.handler.call(this, the, args);
                        }
                    } else {
                        event.handler.call(this, the, args);
                    }
                }
            }
        },

        /**
         * 添加事件
         *
         * @param name {string} 事件名称
         * @param handler {function} 回调
         * @param one {boolean} 是否一次性
         */
        addEvent: function (name, handler, one) {
            the.events.push({
                name: name,
                handler: handler,
                one: one,
                fired: false
            });
        }
    };

    // 公开方法
    /**
     * 设置默认option
     *
     * @param options {object} 选项
     */
    the.setDefaults = function (options) {
        defaultOptions = options;
    };
    /**
     * 当前是否显示
     *
     * @returns {*|boolean}
     */
    the.isShown = function () {
        return Plugin.isShown();
    };
    /**
     * 隐藏
     *
     * @returns {*|undefined}
     */
    the.hide = function () {
        return Plugin.hide();
    };
    /**
     * 显示
     * @returns {*|undefined}
     */
    the.show = function () {
        return Plugin.show();
    };
    /**
     * 绑定事件
     *
     * @param name {string} 事件名称
     * @param handler {function} 回调
     * @returns {*|void}
     */
    the.on = function (name, handler) {
        return Plugin.addEvent(name, handler);
    };
    /**
     * 绑定一次性事件
     *
     * @param name {string} 事件名称
     * @param handler {function} 回调
     * @returns {*|void}
     */
    the.one = function (name, handler) {
        return Plugin.addEvent(name, handler, true);
    };

    Plugin.construct.apply(the, [options]);
    return the;
};